/* All based on https://cstack.github.io/db_tutorial      */

#include <string>

#include <iostream>

#include "SQLCompiler.hpp"
#include "VM.hpp"

// 打印终端符号
inline void print_prompt() {
    std::cout << "db> ";
}

void read_input(std::string& input_buffer) {
    using std::ios_base;
    READ:
    std::getline(std::cin, input_buffer);

    if (input_buffer.empty()) {
        print_prompt();
        goto READ;
    }

    auto state = std::cin.rdstate();
    if (state == ios_base::badbit) { // 不可恢复错误
        std::cout << "Error reading input\n";
        std::exit(EXIT_FAILURE);
    } else if (state == ios_base::failbit) {
        std::cout << "Found some failbits in your input, try again !\n";
        std::cin.clear();
        print_prompt();
        goto READ;  // 不用递归, 减少开辟函数栈的消耗
    }

    return ;
}

int main(int argc, char* argv[]) {
    // 修改
    if (argc < 2) {
        std::cout << "Must supply a database filename.\n";
        exit(EXIT_FAILURE);
    }
    std::string input_buffer;
    SQLCompiler compiler;
    VM vm(argv[1]);

    while (true) {
        print_prompt();
        read_input(input_buffer);

        CompileResult compile_result = compiler.compile(input_buffer);

        switch (compile_result.meta_result) 
        {
        case MetaCommandResult::Exit:
            goto EXIT;
        case MetaCommandResult::Success:
            break;
        case MetaCommandResult::UnrecognizedCommand:
            std::cout << "Unrecognized command '" << input_buffer << "'.\n";
            continue;
        }

        switch (compile_result.prepare_result)
        {
        case PrepareResult::Success:
            break;
        case PrepareResult::StringTooLong:
            std::cout << "String is too long.\n";
            continue;
        case PrepareResult::NegativeID:
            std::cout << "ID must be postive.\n";
            continue;
        case PrepareResult::SyntaxError:
            std::cout << "Syntax error. Could not parse statement.\n";
            continue;
        case PrepareResult::UnrecognizedStatement:
            std::cout << "Unrecognized keyword at start of '" << input_buffer << "'.\n";
            continue;
        }

        ExecuteResult execute_result =  vm.execute(compile_result.state);
        
        switch (execute_result)
        {
        case ExecuteResult::Success:
            std::cout << "Executed.\n";
            break;
        case ExecuteResult::TableFull:
            std::cout << "Error: Table is Full.\n";
            break;
        case ExecuteResult::TableEmpty:
            std::cout << "Error: Table is Empty.\n";
            break;
        case ExecuteResult::DuplicateKey:
            std::cout << "Error: Duplicate key.\n";
            break;
        case ExecuteResult::Unexpected:
            std::cout << "Unexpected Error.\n";
            exit(EXIT_FAILURE);
        }
    }
    EXIT:
    return 0;
}